// main.go
package main

import (
	"fmt"
	"net"
	"os"
	"sync"
	"sync/atomic"
	"time"

	pb "goHupuWalker/gproto"

	log "github.com/alecthomas/log4go"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)

var TimeOutInMin int32 = 5
var runMutex sync.Mutex
var running bool
var runtimer *time.Timer = time.NewTimer(time.Minute * time.Duration(TimeOutInMin))

func kickoffHupuWalk() bool {
	runMutex.Lock()
	defer runMutex.Unlock()
	if running {
		return false
	}

	running = true
	runtimer.Stop()
	go func() {
		hupuWalk(false)
		timeout := atomic.LoadInt32(&TimeOutInMin)
		runtimer.Reset(time.Minute * time.Duration(timeout))
		running = false
	}()

	return true
}

func timerloop() {
	for {
		<-runtimer.C
		kickoffHupuWalk()
	}
}

type HupuWalkerServer struct{}

func (self *HupuWalkerServer) SetDuration(ctx context.Context, in *pb.SetDurationRequest) (*pb.HupuWalkerReply, error) {
	log.Info("SetDuration called")
	runtimer.Stop()
	atomic.StoreInt32(&TimeOutInMin, in.GetDurationInMin())
	runtimer.Reset(time.Minute * time.Duration(in.GetDurationInMin()))

	return &pb.HupuWalkerReply{ErrorCode: 0, ErrorMsg: ""}, nil
}

func (self *HupuWalkerServer) Start(ctx context.Context, in *pb.StartRequest) (*pb.HupuWalkerReply, error) {
	log.Info("Start called")

	ret := &pb.HupuWalkerReply{ErrorCode: 0, ErrorMsg: ""}

	if !kickoffHupuWalk() {
		log.Info("Currently Running, reject")
		ret.ErrorCode, ret.ErrorMsg = 11, "HupuWalker is currently running, please wait a moment"
	}

	return ret, nil
}

func main() {
	if false {
		log.Global["stdout"].Level = log.WARNING
	} else {
		log.Global["stdout"].Level = log.INFO
	}
	defer log.Close()

	if len(os.Args) != 2 {
		fmt.Fprintln(os.Stderr, "usage: server.exe <target email>")
		os.Exit(1)
	}

	InitHupuSego()
	hupuWalk(true)
	go timerloop()

	lis, err := net.Listen("tcp", ":50001")
	if err != nil {
		log.Error("Open port failed, %v", err)
		return
	}

	server := grpc.NewServer()
	pb.RegisterHupuWalkerServer(server, &HupuWalkerServer{})
	reflection.Register(server)
	err = server.Serve(lis)
	if err != nil {
		log.Error("Failed to Serve: %v", err)
	}

}
